[SPIR-V] Add clang builtin for subgroup shuffles#174655
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: Joseph Huber (jhuber6) ChangesSummary: I don't know SPIR-V very well so let me know if this is the proper Full diff: https://github.com/llvm/llvm-project/pull/174655.diff 5 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index d2ef6f99a0502..e31758b889d3d 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -21,3 +21,5 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
+
+def subgroup_shuffle : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 9b0ca3eb0035a..1ea23e8c2195f 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -109,6 +109,15 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
Call->addRetAttr(llvm::Attribute::AttrKind::NoUndef);
return Call;
}
+ case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ assert(E->getArg(1)->getType()->hasIntegerRepresentation());
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/getTypes().ConvertType(E->getArg(0)->getType()),
+ Intrinsic::spv_wave_readlane, ArrayRef<Value *>{X, Y}, nullptr,
+ "spv.shuffle");
+ }
case SPIRV::BI__builtin_spirv_num_workgroups:
return Builder.CreateIntrinsic(
/*ReturnType=*/getTypes().ConvertType(E->getType()),
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index fa30e149c209a..5f3dd71f28c67 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -380,6 +380,32 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+ if (SemaRef.checkArgCount(TheCall, 2))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ if (!ArgTyA->isIntegerType() && !ArgTyA->isFloatingType()) {
+ SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << /* ordinal */ 1 << /* scalar */ 1 << /* no int */ 0
+ << /* no fp */ 0 << ArgTyA;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ if (!ArgTyB->isIntegerType()) {
+ SemaRef.Diag(B.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << /* ordinal */ 2 << /* scalar */ 1 << /* int */ 1 << /* no fp */ 0
+ << ArgTyB;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
index bff850b3622b9..7142dbbc2be73 100644
--- a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
+++ b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
@@ -104,3 +104,11 @@
[[clang::sycl_external]] unsigned int test_subgroup_local_invocation_id() {
return __builtin_spirv_subgroup_local_invocation_id();
}
+
+// CHECK: @{{.*}}test_subgroup_shuffle{{.*}}(
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: tail call float @llvm.spv.wave.readlane.f32(float %f, i32 %i)
+//
+[[clang::sycl_external]] float test_subgroup_shuffle(float f, int i) {
+ return __builtin_spirv_subgroup_shuffle(f, i);
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
index 0d98a552bb1b9..43b2de4e31485 100644
--- a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
+++ b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
@@ -75,3 +75,9 @@ void test_subgroup_local_invocation_id() {
__builtin_spirv_subgroup_local_invocation_id();
__builtin_spirv_subgroup_local_invocation_id(0); // expected-error{{too many arguments to function call, expected 0, have 1}}
}
+
+void test_subgroup_shuffle(int i, float f, int *p) {
+ __builtin_spirv_subgroup_shuffle(f, i);
+ __builtin_spirv_subgroup_shuffle(p, i); // expected-error{{1st argument must be a scalar type}}
+ __builtin_spirv_subgroup_shuffle(i, f); // expected-error{{2nd argument must be a scalar integer}}
+}
|
|
@llvm/pr-subscribers-backend-spir-v Author: Joseph Huber (jhuber6) ChangesSummary: I don't know SPIR-V very well so let me know if this is the proper Full diff: https://github.com/llvm/llvm-project/pull/174655.diff 5 Files Affected:
diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index d2ef6f99a0502..e31758b889d3d 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -21,3 +21,5 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
+
+def subgroup_shuffle : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 9b0ca3eb0035a..1ea23e8c2195f 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -109,6 +109,15 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
Call->addRetAttr(llvm::Attribute::AttrKind::NoUndef);
return Call;
}
+ case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+ Value *X = EmitScalarExpr(E->getArg(0));
+ Value *Y = EmitScalarExpr(E->getArg(1));
+ assert(E->getArg(1)->getType()->hasIntegerRepresentation());
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/getTypes().ConvertType(E->getArg(0)->getType()),
+ Intrinsic::spv_wave_readlane, ArrayRef<Value *>{X, Y}, nullptr,
+ "spv.shuffle");
+ }
case SPIRV::BI__builtin_spirv_num_workgroups:
return Builder.CreateIntrinsic(
/*ReturnType=*/getTypes().ConvertType(E->getType()),
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index fa30e149c209a..5f3dd71f28c67 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -380,6 +380,32 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+ if (SemaRef.checkArgCount(TheCall, 2))
+ return true;
+
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ if (!ArgTyA->isIntegerType() && !ArgTyA->isFloatingType()) {
+ SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << /* ordinal */ 1 << /* scalar */ 1 << /* no int */ 0
+ << /* no fp */ 0 << ArgTyA;
+ return true;
+ }
+
+ ExprResult B = TheCall->getArg(1);
+ QualType ArgTyB = B.get()->getType();
+ if (!ArgTyB->isIntegerType()) {
+ SemaRef.Diag(B.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << /* ordinal */ 2 << /* scalar */ 1 << /* int */ 1 << /* no fp */ 0
+ << ArgTyB;
+ return true;
+ }
+
+ QualType RetTy = ArgTyA;
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
index bff850b3622b9..7142dbbc2be73 100644
--- a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
+++ b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
@@ -104,3 +104,11 @@
[[clang::sycl_external]] unsigned int test_subgroup_local_invocation_id() {
return __builtin_spirv_subgroup_local_invocation_id();
}
+
+// CHECK: @{{.*}}test_subgroup_shuffle{{.*}}(
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: tail call float @llvm.spv.wave.readlane.f32(float %f, i32 %i)
+//
+[[clang::sycl_external]] float test_subgroup_shuffle(float f, int i) {
+ return __builtin_spirv_subgroup_shuffle(f, i);
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
index 0d98a552bb1b9..43b2de4e31485 100644
--- a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
+++ b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
@@ -75,3 +75,9 @@ void test_subgroup_local_invocation_id() {
__builtin_spirv_subgroup_local_invocation_id();
__builtin_spirv_subgroup_local_invocation_id(0); // expected-error{{too many arguments to function call, expected 0, have 1}}
}
+
+void test_subgroup_shuffle(int i, float f, int *p) {
+ __builtin_spirv_subgroup_shuffle(f, i);
+ __builtin_spirv_subgroup_shuffle(p, i); // expected-error{{1st argument must be a scalar type}}
+ __builtin_spirv_subgroup_shuffle(i, f); // expected-error{{2nd argument must be a scalar integer}}
+}
|
|
Apparently |
The team could look into this case, but the answer is usually because we use builtins as alias for codegen that needs to support multiple targets. A secondary more minor reason is it gives us tighter control of sema rules. |
Alright, I'm mostly just interested in a basis set of SPIR-V builtins that will let me port some existing code. I think the only missing one if this one works is a |
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
|
Random question, why are the intrinsics called |
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and #174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
subgroup (SPIRV), wave (DX), warp (Nvidia), wavefront (AMD). Are all the same thing. We picked wave because its the only one that seems to be used as an api-level name and not a harware unit. It was also the only one that shares a name with a harware unit. More importantly the intrinsic toggling we are doing is very basic between DirectX and SPIRV so the intrinsic names need to match. |
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm/llvm-project#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
It mostly became this way because when we started spirv in the frontend wasn't a thing yet. It doesn't have to stay this way in |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
Summary: This is an attempt to begin filling out some missing pieces to allow more generic compute code to use SPIR-V flavored builtins. This should provide the basic shuffle operation. The next most important one is the ballot, but I don't think we have an IR intrinsic for that yet. I don't know SPIR-V very well so let me know if this is the proper function with the proper semantic checks. Sema test nit Update sema checking for int argument
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
Summary: This is an attempt to begin filling out some missing pieces to allow more generic compute code to use SPIR-V flavored builtins. This should provide the basic shuffle operation. The next most important one is the ballot, but I don't think we have an IR intrinsic for that yet. I don't know SPIR-V very well so let me know if this is the proper function with the proper semantic checks.
Summary: #174862 and #174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
…910) Summary: llvm/llvm-project#174862 and llvm/llvm-project#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm/llvm-project#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need. (cherry picked from commit f8b68c7)
Summary: llvm/llvm-project#174862 and llvm/llvm-project#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these. (cherry picked from commit 5c43243)
Summary: This patch adds an LLVM intrinsic and lowering for a subgroup ballot and a corresponding clang builtin. This uses the already present support but provides in a way accessible to other targets. With this and llvm#174655 we should be able to most of the basic functions, like shuffling, active masks, and reductions. More work will be needed for canonicalizing / exposing the SPIR-V functions, but these are the fundamental builtins I need.
Summary: This is an attempt to begin filling out some missing pieces to allow more generic compute code to use SPIR-V flavored builtins. This should provide the basic shuffle operation. The next most important one is the ballot, but I don't think we have an IR intrinsic for that yet. I don't know SPIR-V very well so let me know if this is the proper function with the proper semantic checks.
Summary: llvm#174862 and llvm#174655 provided the intrinsics required to get the fundamental operations working for these. This patch sets up the basic support (as far as I know). This should be the first step towards allowing SPIR-V to build things like the LLVM libc and the OpenMP Device Runtime Library. The implementations here are intentionally inefficient, such as not using the dedicated SPIR-V opcode for read firstlane. This is just to start and hopefully start testing things later. Would appreciate someone more familiar with the backend double-checking these.
Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.
I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.